/**
 * 
 */
package marpg.network;

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.PrintStream;
import java.net.Socket;
import java.net.UnknownHostException;

import marpg.core.Agent;

/**
 * @author Steven
 * 
 */
public class ConnectionHandler implements Runnable {
	private Agent agent = null;
	private int portNumber = 0;
	private String host = null;

	// clientSocket: the client socket
	// socketOut: the output to socket
	// socketIn: the input from socket
	private Socket clientSocket = null;
	private PrintStream socketOut = null;
	private BufferedReader socketIn = null;
	private BufferedReader commandIn = null;

	private Thread messageHandlerThread = null;
	private boolean isQuit = false;

	public void setup(Agent agent, String host, int portNumber) {
		this.agent = agent;
		this.host = host;
		this.portNumber = portNumber;
	}

	public void connect() {
		if ((agent == null) || (agent.getAgentName() == null) || (host == null) || (host.trim().equals(""))
				|| portNumber <= 0) {
			throw new IllegalArgumentException("Invalid agent, host, or port number!");
		}

		// Initialization section:
		// Try to open a socket on a given host and port
		// Try to open input and output streams
		try {
			clientSocket = new Socket(host, portNumber);
			commandIn = new BufferedReader(new InputStreamReader(System.in));
			socketOut = new PrintStream(clientSocket.getOutputStream());
			socketIn = new BufferedReader(new InputStreamReader(clientSocket.getInputStream()));
		} catch (UnknownHostException e) {
			System.err.println("Don't know about host " + host);
		} catch (IOException e) {
			System.err.println("Couldn't get I/O for the connection to the host " + host);
		}

		// If everything has been initialized then we want to write some data
		// to the socket we have opened a connection to on port port_number
		if ((clientSocket != null) && (socketOut != null) && (socketIn != null)) {
			try {
				// Create a thread to read from the server
				messageHandlerThread = new Thread(this);
				messageHandlerThread.start();

				// Send login message to server
				agent.doLogin();
				
				// Read user command
				while (true) {
					String command = commandIn.readLine();
					sendMessage(command);

					if ("/quit".equals(command)) {
						break;
					}
				}

				// Clean up
				isQuit = true;
				socketOut.close();
				socketIn.close();
				clientSocket.close();
			} catch (IOException e) {
				System.err.println("IOException:  " + e);
			}
		}

	}

	@Override
	public void run() {
		while (!isQuit) {
			receiveMessage();
		}
	}

	public void receiveMessage() {
		try {
			String message = socketIn.readLine();
			if (message != null) {
				agent.receiveMessage(message);
			}
		} catch (IOException e) {
			if (!isQuit) {
				System.err.println("IOException:  " + e);
			}
		}
	}

	public void sendMessage(String message) {
		socketOut.println(message);
	}
}
